{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "using LinearAlgebra"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Diagonalization\n",
    "\n",
    "If we can find a solution $x \\ne 0$ to\n",
    "\n",
    "$$\n",
    "Ax = \\lambda x\n",
    "$$\n",
    "\n",
    "then, for this vector, the matrix $A$ **acts like a scalar**.  $x$ is called an **eigenvector** of $A$, and $\\lambda$ is called an **eigenvalue**.\n",
    "\n",
    "In fact, for an $m \\times m$ matrix $A$, we typically find $m$ linearly independendent eigenvectors $x_1,x_2,\\ldots,x_m$ and $m$ corresponding eigenvalues $\\lambda_1, \\lambda_2, \\ldots, \\lambda_m$.   Such a matrix is called **diagonalizable**.  Most matrices are diagonalizable; we will deal with the rare \"defective\" (non-diagonalizable) case later.\n",
    "\n",
    "Given such a **basis of eigenvectors**, the key idea for using them is:\n",
    "\n",
    "1. Take any vector $x$ and expand it in this basis: $x = c_1 x_1 + \\cdots c_m x_n$, or $x = Xc$ or $c = X^{-1}x$ where $X$ is the matrix whose *columns are the eigenvectors*.\n",
    "\n",
    "2. For each eigenvector $x_k$, the matrix $A$ acts like a scalar $\\lambda_k$.  Multiplication or division corresponds to multiplying/dividing $x_k$ by $\\lambda_k$.  **Solve your problem for each eigenvector by treating A as the scalar λ**.\n",
    "\n",
    "3. Add up the solution to your problem (sum the basis of the eigenvectors).  That is, multiply the new coefficients by $X$.\n",
    "\n",
    "This process of expanding in the eigenvectors, multiplying (or whatever) by λ, and then summing up the eigenvectors times their new coefficients, is expressed algebraically as the following **diagonalization** of the matrix $A$:\n",
    "\n",
    "$$\n",
    "A = X \\Lambda X^{-1}\n",
    "$$\n",
    "\n",
    "where $\\Lambda$ is the **diagonal matrix of the eigenvalues** and $X = \\begin{pmatrix} x_1 & x_2 & \\cdots & x_m \\end{pmatrix}$ from above."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Expanding in an Eigenvector Basis\n",
    "\n",
    "For example, consider the matrix\n",
    "\n",
    "$$\n",
    "A = \\begin{pmatrix} 1 & 1 \\\\ -2 & 4 \\end{pmatrix}\n",
    "$$\n",
    "\n",
    "whose eigenvalues are $\\lambda_1 = 2$ and $\\lambda_2 = 3$ and whose eigenvectors are $x_1 = \\begin{pmatrix}1\\\\1\\end{pmatrix}$ and $x_2 = \\begin{pmatrix}1\\\\2\\end{pmatrix}$.\n",
    "\n",
    "We put these eigenvectors into a matrix $X = \\begin{pmatrix} x_1 & x_2 \\end{pmatrix} = \\begin{pmatrix} 1 & 1 \\\\ 1 & 2 \\end{pmatrix}$.  The matrix is invertible: $A$ is *diagonalizable*, since the eigenvectors form a *basis*. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2-element Vector{Float64}:\n",
       " 2.0\n",
       " 3.0"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "A = [1 1\n",
    "    -2 4]\n",
    "eigvals(A)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2×2 Matrix{Int64}:\n",
       " 1  1\n",
       " 1  2"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X = [1 1\n",
    "     1 2]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To write any vector $x$ in the basis of eigenvectors, we just want $x = Xc$ or $c = X^{-1} x$.  For example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2-element Vector{Float64}:\n",
       "  2.0\n",
       " -1.0"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = [1,0]\n",
    "c = X \\ x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "i.e. $x = \\begin{pmatrix} 1 \\\\ 0 \\end{pmatrix} = 2 \\begin{pmatrix} 1 \\\\ 1 \\end{pmatrix} - \\begin{pmatrix} 1 \\\\ 2 \\end{pmatrix}$, which is obviously correct."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "$Ax = \\lambda_1 c_1 x_1 + \\lambda_2 c_2 x_2$, or equivalently\n",
    "$$\n",
    "Ax = X \\begin{pmatrix} \\lambda_1 c_1 \\\\ \\lambda_2 c_2 \\end{pmatrix} = \n",
    "     X \\underbrace{\\begin{pmatrix} \\lambda_1 &  \\\\  &  \\lambda_2  \\end{pmatrix}}_\\lambda c\n",
    "     = X \\Lambda X^{-1} x\n",
    "$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2-element Vector{Int64}:\n",
       "  1\n",
       " -2"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "A*x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2×2 Diagonal{Int64, Vector{Int64}}:\n",
       " 2  ⋅\n",
       " ⋅  3"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Λ = Diagonal([2, 3])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2-element Vector{Float64}:\n",
       "  1.0\n",
       " -2.0"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X*Λ*c"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2-element Vector{Float64}:\n",
       "  1.0\n",
       " -2.0"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X * Λ * inv(X) * x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Since this is true for *every* $x$, it means $\\boxed{A = X \\Lambda X^{-1}}$:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2×2 Matrix{Float64}:\n",
       "  1.0  1.0\n",
       " -2.0  4.0"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X * Λ / X   # / X is equivalent to multiplying by inv(X), but is more efficient"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Another way to see this is to consider $$AX = \\begin{pmatrix} Ax_1 & Ax_2 \\end{pmatrix} = \\begin{pmatrix} \\lambda_1 x_1 & \\lambda_2 x_2 \\end{pmatrix} = X \\Lambda$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2×2 Matrix{Int64}:\n",
       " 2  3\n",
       " 2  6"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "A*X"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2×2 Matrix{Int64}:\n",
       " 2  3\n",
       " 2  6"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X*Λ"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "It follows that $A = X\\Lambda X^{-1}$ or $\\boxed{\\Lambda = X^{-1} A X}$:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2×2 Matrix{Float64}:\n",
       " 2.0  0.0\n",
       " 0.0  3.0"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X \\ A * X"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The key thing is that this works for **any matrix, as long as the eigenvectors form a basis**. Such a matrix is called **diagonalizable**, and it turns out that this is true for almost all matrices; we will deal with the rare exceptions.\n",
    "\n",
    "Thus, eigenproblems join LU factorization (Gaussian elimination) and QR factorization (Gram–Schmidt): the eigensolutions are **equivalent to a matrix factorization**.  This is extremely useful in helping us think *algebraically* about using eigenvalues and eigenvectors, because it lets us work with them *all at once*."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Change of Basis and Similar Matrices"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A key concept in linear algebra, *especially* for eigenproblems, is a *change of basis*.   If $S$ is an $m\\times m$ invertible matrix, then we know its columns form a *basis* for $\\mathbb{R}^m$.  Writing any $x$ in this basis is simply $x=Sc$, i.e. coordinates $c = S^{-1} x$ in the new basis (the new \"coordinate system\").\n",
    "\n",
    "If we have a matrix $A$ representing a linear operation $y=Ax$, we can also try to write the *same* linear operation in a *new* coordinate system.  That is, if we write $x=Sc$ and $y=Sd$, then what is the matrix relating $c$ and $d$?  This is easy to compute:\n",
    "$$\n",
    "d = S^{-1} y = S^{-1} Ax = S^{-1} A S c,\n",
    "$$\n",
    "so the matrix $\\boxed{B = S^{-1} A S}$ is represent the same operation as $A$ but in the new coordinate system.\n",
    "\n",
    "In linear algebra, we say that $A$ and $B$ are **similar matrices**.  That is, B is similar to A if and only if $B = S^{-1} A S$ for some invertible matrix S.   It also follows that $A = SBS^{-1} = (S^{-1})^{-1} B (S^{-1})$, i.e. if B is similar to A using S, then A is similar to B using $S^{-1}$.\n",
    "\n",
    "For example, we can choose a random 2×2 S to write our matrix A from above in a new coordinate system:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2×2 Matrix{Float64}:\n",
       "  0.34504   1.3915\n",
       " -0.486365  1.30546"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "S = randn(2,2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1.1272143106064274"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "det(S) # a random S is almost certainly nonsingular"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2×2 Matrix{Float64}:\n",
       "  3.08981   0.11279\n",
       " -0.867718  1.91019"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "B = S \\ A * S   # same as inv(S) * A * S, but more efficient since it avoids the explicit inverse"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A key fact is that **similar matrices have the same eigenvalues** (but different eigenvectors):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2-element Vector{Float64}:\n",
       " 1.9999999999999991\n",
       " 3.000000000000001"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "eigvals(B)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This is easy to show in a variety of ways.\n",
    "\n",
    "For example, if $Ax=\\lambda x$, since $A=SBS^{-1}$, we have $ SBS^{-1} x = \\lambda x$, or\n",
    "$$\n",
    "B(S^{-1}x) = \\lambda (S^{-1}x)\n",
    "$$\n",
    "so **S⁻¹x is an eigenvector of B with the *same* eigenvalue λ**!\n",
    "\n",
    "In contrast, multiplying $A$ only on *one* side by some matrix $S$ will typically change the eigenvalues:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2-element Vector{ComplexF64}:\n",
       " 1.1487471858694138 - 2.3331664678277177im\n",
       " 1.1487471858694138 + 2.3331664678277177im"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "eigvals(A * S)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Another way of seeing this is by looking at the characteristic polynomial:\n",
    "\n",
    "$$\n",
    "\\det(A - \\lambda I) = \\det(SBS^{-1} - \\lambda I) = \\det \\left[ S (B - \\lambda I) S^{-1}   \\right]\n",
    "= \\det(S) \\det(B - \\lambda I) \\det(S^{-1}) = \\det(B - \\lambda I)\n",
    "$$\n",
    "\n",
    "i.e. **similar matrices have the same characteristic polynomial**.\n",
    "\n",
    "(Here, we used the product rule for determinants and the fact that $\\det(S^{-1}) = 1/\\det(S)$.)\n",
    "\n",
    "If we set λ=0, we see that $\\det A = \\det B$, i.e. **similar matrices have the same determinant**."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(6.0, 5.999999999999999)"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "det(A), det(B)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Determinant = Product of λ’s\n",
    "\n",
    "In the new language, we see that diagonalization $A = X \\Lambda X^{-1}$ is the same thing as saying that **A is similar to a diagonal matrix (of eigenvalues)**.  That is, there is a basis (coordinate system) in which A is diagonal.\n",
    "\n",
    "From above, $\\det A = \\det \\Lambda = \\lambda_1 \\lambda_2 \\cdots \\lambda_m$.  That is, the **determinant is the product of the eigenvalues**.\n",
    "\n",
    "(Technically, we have only shown this for diagonalizable matrices, but it turns out to be true in general.)\n",
    "\n",
    "Let's try it:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "6.0"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "det(A)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This is the same as the product of A's eigenvalues:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "6"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "2 * 3"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Equivalently, using Julia's `prod` function (which computes the product of the elements of a list):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "6.0"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "prod(eigvals(A))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can also try it for some large matrices:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1.6680449397144425e78"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Abig = randn(100,100)\n",
    "det(Abig)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1.6680449397143506e78 - 1.3679861476883116e62im"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "prod(eigvals(Abig))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "It also follows that the log of the determinant is the sum of the logs of the eigenvalues.\n",
    "\n",
    "Julia has a built-in function `logabsdet` to compute the log of the absolute value of the determinant, which should be the sum of the logs of the absolute values of the eigenvalues.  (There is also a `logdet` function to compute the log without the absolute value, but then we need to deal with complex numbers.)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(180.11328949938405, 1.0)"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "logabsdet(Abig) # the log of the absolute value of the determinant, and the sign"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "180.113289499384"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s = sum(log.(abs.(eigvals(Abig)))) # the sum of the logs of |λ|"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If we try to compute the determinant of an even bigger matrix, we run into a problem: in the default precision, a computer can't represent numbers bigger than $10^{308}$ or so, and instead gives `Inf` (for \"infinity\"):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "-Inf"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Abigger = randn(1000,1000)\n",
    "det(Abigger)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1.7976931348623157e308"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "floatmax(Float64) # the problem is that there is a maximum value the computer can represent, beyond which it gives \"Inf\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "But the log is fine:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(2954.073853516206, -1.0)"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "logabsdet(Abigger) # but the log is fine"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2954.0738535162086"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s = sum(log.(abs.(eigvals(Abigger)))) # the sum of the logs of |λ|"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Trace = Sum of λ’s"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Another important quantity for a square matrix, which we haven't covered yet, is the [trace](https://en.wikipedia.org/wiki/Trace_(linear_algebra)).  The trace is defined as the **sum of the diagonal elements** of any matrix.  By plugging in the definition of matrix multiplication, one can quickly show that the trace has a crucial property:\n",
    "\n",
    "$$\n",
    "\\operatorname{trace} (AB) = \\operatorname{trace}(BA)\n",
    "$$\n",
    "\n",
    "It follows that **similar matrices have the same trace**, since if $A=SBS^{-1}$ then \n",
    "\n",
    "$$\n",
    "\\operatorname{trace} (A) = \\operatorname{trace}(SBS^{-1}) = \\operatorname{trace}(S^{-1}SB) = \\operatorname{trace}(B)\n",
    "$$\n",
    "\n",
    "In particular, since A and Λ are similar, this means that the **trace of a matrix is the sum of the eigenvalues**!\n",
    "\n",
    "Let's check:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "5"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tr(A)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Yup, this is the sum of the eigenvalues:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "5"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "2 + 3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "5.0"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sum(eigvals(A))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's try it for our bigger example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4.625235324319982"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tr(Abig)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4.625235324319927 + 1.2434497875801753e-14im"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sum(eigvals(Abig))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Diagonalization and Matrix Powers\n",
    "\n",
    "We've already seen that if $Ax = \\lambda x$ then $A^n x = \\lambda^n x$ (for both positive and negative $n$): **if x is an eigenvector of A, then it is also an eigenvector of Aⁿ with the eigenvalue raised to the n-th power**.\n",
    "\n",
    "There is another cute way to see this for diagonalizable matrices.  If $A = X\\Lambda X^{-1}$, then for $n \\ge 0$\n",
    "\n",
    "$$\n",
    "A^n = \\underbrace{AAA\\cdots A}_{n\\mbox{ times}} \n",
    "    = \\underbrace{X\\Lambda X^{-1}X\\Lambda X^{-1}X\\Lambda X^{-1}\\cdots X\\Lambda X^{-1}}_{n\\mbox{ times}} = X\\Lambda^n X^{-1}\n",
    "$$\n",
    "because all of the $X$ terms *cancel* except the first and last ones.  $\\Lambda^n$ is just the diagonal matrix with $\\lambda_1^n, \\lambda_2^n, \\ldots$ on the diagonal.\n",
    "\n",
    "So, since we have the diagonalization of $A^n$, we immediately see that its eigenvectors are $X$ (same as for $A$) and its eigenvalues are $\\lambda^n$.\n",
    "\n",
    "Since $A^{-1}x = \\lambda^{-1} x$ for an eigenvector $x$, it immediately follows that $A^{-1} = X \\Lambda^{-1} X^{-1}$ where $\\Lambda^{-1}$ is the diagonal matrix with $\\lambda_k^{-1}$ on the diagonal.  Similarly for $A^{-n} = X \\Lambda^{-n} X^{-1}$."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2×2 Matrix{Int64}:\n",
       "  1  1\n",
       " -2  4"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "A = [1 1\n",
    "    -2 4]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2-element Vector{Float64}:\n",
       " 2.0\n",
       " 3.0"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "eigvals(A)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's check that the eigenvalues of $A^4$ are $2^4 = 16$ and $3^4 = 81$:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2-element Vector{Float64}:\n",
       " 16.0\n",
       " 81.0"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "eigvals(A^4)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Remember, these are the eigenvectors $X$ of $A$ with the first component normalized to 1 (via the `./` \"broadcasting\" operator; similar operations can be found in [Python](https://docs.scipy.org/doc/numpy/user/basics.broadcasting.html) and [Matlab](https://www.mathworks.com/help/matlab/ref/bsxfun.html)):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2×2 Matrix{Float64}:\n",
       " 1.0  1.0\n",
       " 1.0  2.0"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X = eigvecs(A)\n",
    "X = X ./ X[1,:]'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's check that the eigenvectors $X'$ of $A^4$ are the same:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2×2 Matrix{Float64}:\n",
       " 1.0  1.0\n",
       " 1.0  2.0"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "X′ = eigvecs(A^4)\n",
    "X′ = X′ ./ X′[1,:]'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Similarly for $A^{-1}$, whose eigenvalues should be 1/2 and 1/3:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2-element Vector{Float64}:\n",
       " 0.33333333333333337\n",
       " 0.4999999999999999"
      ]
     },
     "execution_count": 40,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "eigvals(inv(A))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that a **matrix is invertible if and only if its eigenvalues are all nonzero**.\n",
    "\n",
    "In fact an eigenvector of $A$ for $\\lambda = 0$ has another name we've already seen: it is a **nonzero** vector in the **nullspace** $N(A)$.   Only matrices with $N(A) = \\{\\vec{0}\\}$ (remember, $\\vec{0}$ is not allowed as an eigenvector) are invertible."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Matrix square roots\n",
    "\n",
    "One really cool thing that diagonalization allows us to do easily is to compute $A^n$ for **non-integer powers n**.   For example, we can now see how to find the [square root of a matrix](https://en.wikipedia.org/wiki/Square_root_of_a_matrix), at least for diagonalizable matrices.\n",
    "\n",
    "If $A$ is a square matrix, its square root $\\sqrt{A} = A^{1/2}$ is just a matrix so that $A^{1/2} A^{1/2} = A$.  But how would we find such a matrix?\n",
    "\n",
    "As usual, for eigenvalues it is easy: if $Ax=\\lambda x$, then we obviously want $A^{1/2} x = \\lambda^{1/2} x$.  If $A$ is diagonalizable and we do this for *every* eigenvalue/vector, we get the diagonalization:\n",
    "\n",
    "$$\n",
    "\\sqrt{A} = A^{1/2} = X \\underbrace{\\begin{pmatrix} \\sqrt{\\lambda_1} & & & \\\\ & \\sqrt{\\lambda_2} & & \\\\ & & \\ddots & \\\\ & & & \\sqrt{\\lambda_m} \\end{pmatrix}}_\\sqrt{\\Lambda} X^{-1}\n",
    "$$\n",
    "(Obviously, this may give a complex matrix if any eigenvalues are negative or complex.)\n",
    "\n",
    "Does this have the property that $A^{1/2} A^{1/2} = A$? Yes!  $X \\sqrt{\\Lambda} X^{-1} X \\sqrt{\\Lambda} X^{-1} = X \\sqrt{\\Lambda} \\sqrt{\\Lambda} X^{-1} = A$, since obviously $\\sqrt{\\Lambda} \\sqrt{\\Lambda} = \\Lambda$ from the definition above.\n",
    "\n",
    "Let's try it:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2-element Vector{Float64}:\n",
       " 1.4142135623730951\n",
       " 1.7320508075688772"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sqrt.(eigvals(A)) # takes the square root (elementwise) of each eigenvalue"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2×2 Diagonal{Float64, Vector{Float64}}:\n",
       " 1.41421   ⋅ \n",
       "  ⋅       1.73205"
      ]
     },
     "execution_count": 42,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Diagonal(sqrt.(eigvals(A))) # the diagonal matrix √Λ"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2×2 Matrix{Float64}:\n",
       "  1.09638   0.317837\n",
       " -0.635674  2.04989"
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Asqrt = X * Diagonal(sqrt.(eigvals(A))) / X   # the √A matrix"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2×2 Matrix{Float64}:\n",
       "  1.0  1.0\n",
       " -2.0  4.0"
      ]
     },
     "execution_count": 44,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Asqrt * Asqrt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Hooray, it squared to $A$ as desired!\n",
    "\n",
    "Julia `sqrt` will compute the matrix square root for you if you give it a square-matrix argument.   (It is more general than our approach above, because it works even for non-diagonalizable matrices.)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2×2 Matrix{Float64}:\n",
       "  1.09638   0.317837\n",
       " -0.635674  2.04989"
      ]
     },
     "execution_count": 45,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sqrt(A)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's double-check that it is the same as we got from an explicit square root of the eigenvalues:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "true"
      ]
     },
     "execution_count": 46,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sqrt(A) ≈ Asqrt"
   ]
  }
 ],
 "metadata": {
  "@webio": {
   "lastCommId": null,
   "lastKernelId": null
  },
  "kernelspec": {
   "display_name": "Julia 1.8.0",
   "language": "julia",
   "name": "julia-1.8"
  },
  "language_info": {
   "file_extension": ".jl",
   "mimetype": "application/julia",
   "name": "julia",
   "version": "1.8.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
